package com.qdd.freight.util;

/**
 * @ClassName OtherUtils
 * @Description TODO
 * @Author yanpeihao
 * @Date 2019/12/21 22:12
 * @Version 1.0
 **/

public class OtherUtils {
//    package com.qdd.handler;
//
//import com.qdd.entity.Datas;
//import com.qdd.exception.NoGoosShipFoundException;
//import com.qdd.exception.NoShipFieldNameException;
//import com.qdd.exception.NoShipFoundException;
//import com.qdd.mapper.DevileryMapper;
//import com.qdd.mapper.GoodsShipMapper;
//import com.qdd.mapper.LogisticsMapper;
//import com.qdd.pojo.Delivery;
//import com.qdd.pojo.GoodsShip;
//import com.qdd.pojo.Logistics;
//import com.qdd.util.ReflectUtil;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.util.StringUtils;
//import tk.mybatis.mapper.entity.Example;
//
//import java.lang.reflect.Field;
//import java.util.Arrays;
//import java.util.List;
//import java.util.Map;
//import java.util.stream.Collectors;
//
//    /**
//     * 根据运价的组成不同，实现不同的方法，
//     * 最终按照统一的计算规则进行总价计算
//     *
//     * @ClassName AbstractHandler
//     * @Description TODO
//     * @Author yanpeihao
//     * @Date 2019/12/6 21:26
//     * @Version 1.0
//     **/
//
//    public abstract class AbstractHandler {
//
//        @Autowired
//        private GoodsShipMapper goodsShipMapper;
//
//        @Autowired
//        private DevileryMapper devileryMapper;
//
//        @Autowired
//        private LogisticsMapper logisticsMapper;
//
//        abstract public String getShipFieldNameFromInstance() throws NoShipFieldNameException;
//
//        /**
//         * 运价计算抽象方法---由具体实现类实现内部计算逻辑
//         *
//         * @param goodsId
//         * @param entId
//         * @param quantity
//         * @param company
//         * @param consignee
//         * @return
//         */
//        abstract public Datas realHandle(Integer modeId, Integer goodsId, Integer entId, Integer quantity,
//                                         Integer company, String consignee) throws NoGoosShipFoundException;
//
//        /**
//         * 被service调用的主逻辑方法
//         * 通用计算框架，controller层会调用该方法执行判断
//         * DONE
//         * @return
//         */
//        public Datas handelFreight(Integer modeId, Integer goodsId, Integer entId, Integer quantity,
//                                   Integer company, String consignee) throws NoGoosShipFoundException, NoShipFieldNameException, NoShipFoundException {
//            //1.调用实现类的具体实现，获取对应的goodsShip的字段名
//            String fieldName = getShipFieldNameFromInstance();
//
//            if (StringUtils.isEmpty(fieldName)) {
//                System.out.println("未获取到指定的实现类字段名。");
//                return null;
//            }
//            //2.获得goodsShip对象
//            GoodsShip goodsShip = getAppointedGoodsShip(goodsId, entId, quantity);
//            //3.获取所有值不为0的goodsShip对象的快递/物流id
//            Integer shipId = getAppointedShipId(goodsId, entId, quantity, fieldName);
//
//            //调用子类的实现逻辑进行禁运判断，时间和地区，禁运则退出计算
//            if (isForbidon(shipId, consignee)) {
//                System.out.println("禁运中！！！！！！！！！");
//                return null;
//            }
//
//            //调用具体的计算处理器进行结果计算
//            Datas datas = realHandle(modeId, goodsId, entId, quantity, company, consignee);
//            if (datas == null) {
//                return null;
//            }
//
//            //只可能有一个结果
//            return datas;
//        }
//
//        //================================================================================
//
//
//        /**
//         * 实现方法1：启用
//         * 子类可继承的工具方法--确定要使用的goodsShip对象
//         * 无阈值，1条数据
//         * 有阈值，2条数据，取出快递/物流id的list集合
//         *
//         * @param goodsId  商品id
//         * @param entId    仓库id
//         * @param quantity 采购数量
//         * @return
//         */
//        protected GoodsShip getAppointedGoodsShip(Integer goodsId, Integer entId, Integer quantity) throws NoGoosShipFoundException {
//            //获取该商品的goodsShip对象，如果设置了阈值会有两条记录
//            List<GoodsShip> goodsShipList = getGoodsShipListFromDb(goodsId, entId);
//            //判断list的长度，1表示没有阈值，2表示设有阈值
//            //长度为1，说明没有阈值,获取仅有的一行数据
//            if (goodsShipList.size() == 1) {
//                return goodsShipList.get(0);
//            }
//            //如果大于1，比较采购数量和阈值，确定要使用的goodsShip对象
//            //1.比较采购数量和阈值确定symbol值， 1为<=weight,2为>weight
//            int symbol = goodsShipList.stream()
//                    .allMatch(item -> item.getWeight().compareTo(quantity) > 0) ? 1 : 2;
//            GoodsShip goodsShip = goodsShipList.stream()
//                    //找出symbol值匹配的对象
//                    .filter(item -> item.getSymbol() == symbol).findFirst().get();
//            //2.根据比较结果获取要使用的快运对象关联的快递/物流编号
//            return goodsShip ;
//        }
//
//        /* 方法2：备用方法--未启用
//         * 子类可继承的工具方法--通过数据库获取指定的goodsShip对象
//         * @param goodsId  商品id
//         * @param entId    仓库id
//         * @param quantity 采购数量
//         * @return
//         */
////    protected GoodsShip getAppointedGoodsShipFromDb(Integer modeId ,Integer goodsId, Integer entId, Integer quantity) {
////        int symbol = 0;
////        //获取该商品的快运方式记录，如果设置了阈值会有两条记录
////        List<GoodsShip> goodsShipList = getGoodsShipListFromDb(goodsId, entId);
////        //获取为null，说明仓库中没有对应的商品记录，结束请求
////        if (goodsShipList == null || goodsShipList.size() == 0) {
////            return null;
////        }
////        //如果没有阈值，只有1条数据,直接获取返回
////        if (goodsShipList.size() == 1) {
////            symbol = 0;
////        }else {
////            //1.比较采购数量和阈值确定symbol值， 1为<=weight,2为>weight
////            symbol = goodsShipList.stream().allMatch(item -> item.getWeight().compareTo(quantity) > 0) ? 1 : 2;
////        }
////        //调用mapper层从数据库获取快递/物流id
////        Example example = new Example(GoodsShip.class);
////        //根据数据表设置的联合索引查询
////        example.createCriteria()
////                .andEqualTo("entId", entId)
////                .andEqualTo("goodsId", goodsId)
////                .andEqualTo("symbol", symbol);
////
////        GoodsShip goodsShip = goodsShipMapper.selectOneByExample(example);
////        return goodsShip;
////    }
//
//
//
////================================================================================
//
//    /*
//        获取指定的快递/物流shipId，重点是确定当前处理器实现类代表的注解对应的是goodsShip的哪个字段，3种方式：
//        未启用    1.反射解析常量类，通过注解值找出字段名，并进一步转换成GoodsShip对象的对应字段名
//                    既可以确定列，再次使用反射获取该字段的值（已经从数据库取出并封装成了goodsShip对象）
//        未启用    2.传递具体实现类的class对象，反射创建对象获取常量字段中可以对应goodsShip对象的字段的字段名，
//                    利用反射找出goodsShip对象的该字段的值。（也可以换成找出字段名，然后从数据库获取数据。）
//        启用      3.抽象类定义抽象方法getShipFieldName，实现类去实现具体逻辑；定义一个工具类获取指定字段的值；
//                    抽象类的骨架方法先调用实现类的具体方法getShipFieldName得到shipId,在进行后续计算。
//    */
//
//        /*
//         * 实现方式1：备用
//         * 根据modeId+常量+goodsShip，通过反射获取指定的物流/快递id，
//         * 如果后期发现效率不高，切换到备用方法2--通过数据库获取
//         * 可继承的工具方法---获取计算要使用的快递/物流id
//         * @param goodsShip
//         * @param fieldName
//         * @return
//         */
////    protected Integer getAppointedShipId(GoodsShip goodsShip, String fieldName) {
////
////        /*
////            反射获取指定字段的值=goodsShip的所有字段,并找到指定字段名的字段值
////         */
////        //反射获取所有字段
////        Field[] goodsShipFieldList = goodsShip.getClass().getDeclaredFields();
////        //获取goodsShip的指定字段值并返回
////        Integer shipId = Arrays.asList(goodsShipFieldList).stream()
////                .map(item -> (Integer) ReflectUtil.getValue(goodsShip, fieldName))
////                .findFirst().get();
////        return shipId;
////    }
//
//        /**
//         * 实现方式2：
//         * 根据modeId+常量+goodsShip，通过反射获取指定的物流/快递id，
//         * 如果后期发现效率不高，切换到备用方法2--通过数据库获取
//         * 可继承的工具方法---获取计算要使用的快递/物流id
//         * @param goodsId
//         * @param entId
//         * @param quantity
//         * @param fieldName
//         * @return
//         * @throws NoGoosShipFoundException
//         */
//        protected Integer getAppointedShipId(Integer goodsId, Integer entId, Integer quantity, String fieldName) throws NoGoosShipFoundException {
//            //获取该商品的goodsShip对象，如果设置了阈值会有两条记录
//            List<GoodsShip> goodsShipList = null;
//            goodsShipList = getGoodsShipListFromDb(goodsId, entId);
//
//            GoodsShip goodsShip = null;
//            //判断list的长度，1表示没有阈值，2表示设有阈值
//            //长度为1，说明没有阈值,获取仅有的一行数据
//            if (goodsShipList.size() == 1) {
//                goodsShip = goodsShipList.get(0);
//            }else{
//                //1.比较采购数量和阈值确定symbol值， 1为<=weight,2为>weight
//                int symbol = goodsShipList.stream()
//                        .allMatch(item -> item.getWeight().compareTo(quantity) > 0) ? 1 : 2;
//                goodsShip = goodsShipList.stream()
//                        //找出symbol值匹配的对象
//                        .filter(item -> item.getSymbol() == symbol).findFirst().orElse(null);
//            }
//            System.out.println("最终确定的goodsShip" + goodsShip.getId());
//            return (Integer) ReflectUtil.getValue(goodsShip, fieldName);
//        }
//
//        /*
//         * 实现方式3：结合getConstFieldName方法使用
//         */
//
////    protected Integer getAppointedShipId(Integer modeId ,Integer goodsId, Integer entId, Integer quantity) {
////        //获得goodsShip对象
////        GoodsShip goodsShip = getAppointedGoodsShip(goodsId, entId, quantity);
////        //根据modeId获取常量类中的字段名
////        String constFieldName = getConstFieldName(modeId);
////        //获取对象的字段列表
////        List<Field> goodsShipFieldList = getGoodsShipFieldList(goodsId, entId, quantity);
////        //转换为stream流进行过滤查找
////        Integer shipId = goodsShipFieldList.stream().mapToInt(item -> (Integer) ReflectUtil.getValue(goodsShip, constFieldName))
////                .peek(e -> System.out.println(e)).findAny().orElse(0);
////        return shipId;
////    }
////
////
////
////    /* 内部方法----根据modeId获取常量类的字段名，并转换为goodsShip类对应的字段名
////     * @param modeId
////     * @return
////     */
////
////    private String getConstFieldName(Integer modeId){
////        // 1.使用反射,获取所有对应字段的值
////        Field[] ConsFields = ExpressConstants.class.getDeclaredFields();
////        //找出和运输方式有关的字段的集合
////        String constFieldName = Arrays.asList(ConsFields).stream()
////                //找出字段值等于modeId的字段
////                .filter(item -> {
////                    item.setAccessible(true);
////                    try {
////                        return item.get(ReflectUtil.getValue(new ExpressConstants(), item.getName())) == modeId;
////                    } catch (IllegalAccessException e) {
////                        e.printStackTrace();
////                    }
////                    return false;
////                })
////                .map(item -> item.getName().toLowerCase())
////                .map(item -> item.replace("id" , "Id"))
////                .peek(item -> System.out.println("对应的goodsShip字段为：" + item))
////                .findAny().get();
////        return constFieldName;
////    }
////
//
//
////================================================================================
//
//        /* 实现方法1：启用
//         * 内部工具方法--确定要使用的goodsShip对象的快递/物流id集合
//         * @param goodsId  商品id
//         * @param entId    仓库id
//         * @param quantity 采购数量
//         * @return
//         */
//        protected List<Integer> getAppointedShipIds(Integer goodsId, Integer entId, Integer quantity) throws NoGoosShipFoundException {
//            //获取该商品的快运方式记录，如果设置了阈值会有两条记录
//            List<GoodsShip> goodsShipList = getGoodsShipListFromDb(goodsId, entId);
//            //获取为null，说明仓库中没有对应的商品记录，结束请求
//            if (goodsShipList == null || goodsShipList.size() == 0) {
//                return null;
//            }
//        /*
//            如果没有阈值，只有1条数据,直接返回
//         */
//            if (goodsShipList.size() == 1) {
//                return getAppointedShipIds(goodsShipList.get(0));
//            }
//        /*
//            有阈值，有2条数据
//         */
//            //1.比较采购数量和阈值确定symbol值， 1为<=weight,2为>weight
//            int symbol = goodsShipList.stream()
//                    .allMatch(item -> item.getWeight().compareTo(quantity) > 0) ? 1 : 2;
//            //2.根据weight值判断最终的goodsShip对象（symbol值， 1为<=weight,2为>weight）
//            /** DONE 20191217测试根据采购数量获取指定goodsShip对象功能正常*/
//            GoodsShip goodsShip = goodsShipList.stream()
//                    .filter(item -> item.getSymbol() == symbol).findFirst().orElse(null);
//            System.out.println("最终确定的goodsShip" + goodsShip.getId());
//            //3.根据比较结果获取要使用的快运对象关联的快递/物流编号
//            return getAppointedShipIds(goodsShip);
//        }
//
//        /**
//         * 启用
//         * 内部工具方法---反射获取goodsShip对象关联的,不为0的快递/物流id集合
//         *
//         * @param goodsShip
//         * @return
//         */
//        private List<Integer> getAppointedShipIds(GoodsShip goodsShip) {
//            //1.反射获取所有的字段
//            Field[] fields = goodsShip.getClass().getDeclaredFields();
//            //2.找出和运输方式有关的shipId的集合
//            List<Integer> modeIdList = Arrays.asList(fields).stream()
//                    //根据属性名找出包含指定子字符、和计价体系有关的字段field
//                    .filter(item -> item.getName().contains("shipId")
//                            || item.getName().contains("wlId")
//                            || item.getName().contains("transportId"))
//                    .map(item -> (Integer) ReflectUtil.getValue(goodsShip, item.getName()))
//                    .filter(item -> item != 0)
//                    .peek(item -> System.out.print(item + ","))
//                    .collect(Collectors.toList());
//            return modeIdList;
//        }
//
//
////    /*
////     * 禁用
////     * 内部工具方法---反射获取goodsShip对象指定快递/物流字段的值
////     *
////     * @param goodsShip
////     * @return
////
////  */
////    private List<Integer> getAppointedShipIds(GoodsShip goodsShip, String fieldName) {
////        //1.反射获取所有的字段
////        Field[] fields = goodsShip.getClass().getDeclaredFields();
////        //2.找出和运输方式有关的shipId的集合
////        List<Integer> modeIdList = Arrays.asList(fields).stream()
////                .map(item -> (Integer) ReflectUtil.getValue(goodsShip, fieldName))
////                .collect(Collectors.toList());
////        return modeIdList;
////    }
////    /* 禁用
////     * 内部工具方法---反射获取goodsShip对象关联的,不为0的快递/物流id的值d的集合
////     * @param goodsId
////     * @param entId
////     * @param quantity
////     * @return
////     * @throws NoGoosShipFoundException
////     */
////    private List<Integer> getAppointedShipIds(Integer goodsId, Integer entId, Integer quantity) throws NoGoosShipFoundException {
////        //1.调用公共方法从数据库中获取商品快运对象
////        GoodsShip goodsShip = getAppointedGoodsShip(goodsId, entId, quantity);
////        //1.反射获取所有的字段
////        Field[] fields = goodsShip.getClass().getDeclaredFields();
////        //2.找出和运输方式有关的shipId的集合
////        List<Integer> modeIdList = Arrays.asList(fields).stream()
////                //根据属性名找出包含指定子字符、和计价体系有关的字段field
////                .filter(item -> item.getName().contains("shipId")
////                        || item.getName().contains("wlId")
////                        || item.getName().contains("transportId"))
////                .map(item -> (Integer) ReflectUtil.getValue(goodsShip, item.getName()))
////                .filter(item -> item != 0)
////                .peek(item -> System.out.print(item + ","))
////                .collect(Collectors.toList());
////        return modeIdList;
////    }
//
////===================================================================================
//
//        /*
//         * 方法1：禁用
//         * 可继承的方法---反射获取指定商品、仓库、数量下的goodsShip对象的快递/物流相关的，值不为0的字段
//         *
//         * @param goodsId
//         * @param entId
//         * @param quantity
//         * @return
//         */
////    protected List<Field> getAppointedGoodsShipField(Integer goodsId, Integer entId, Integer quantity , String fieldName) throws NoGoosShipFoundException {
////        //1.调用公共方法从数据库中获取商品快运对象
////        GoodsShip goodsShip = getAppointedGoodsShip(goodsId, entId, quantity);
////        //2.反射获取goodsShip所有的字段
////        Field[] fields = goodsShip.getClass().getDeclaredFields();
////        //3.找出和运输方式有关的字段的集合
////        List<Field> fieldList = Arrays.asList(fields).stream()
////                //根据属性名找出包含指定子字符、和计价体系有关的字段field
////                .filter(item -> item.getName().contains("shipId")
////                        || item.getName().contains("wlId")
////                        || item.getName().contains("transportId"))
////                .filter(item -> (Integer) ReflectUtil.getValue(goodsShip, fieldName) != 0)
////                .peek(item -> System.out.print(item + ","))
////                .collect(Collectors.toList());
////        return fieldList;
////    }
//
////================================================================================
//
////    private List<Integer> getGoosShipFieldValues(GoodsShip goodsShip) {
////        //定义list用来存放最终结果
////        List<Integer> valueList = new ArrayList<>();
////        //1.反射获取所有的字段
////        Field[] fields = goodsShip.getClass().getDeclaredFields();
////        //2.找出和运输方式有关的字段的集合
////        List<Field> fieldList = Arrays.asList(fields).stream()
////                //根据属性名找出包含指定子字符、和计价体系有关的字段field
////                .filter(item -> item.getName().contains("shipId")
////                        || item.getName().contains("wlId")
////                        || item.getName().contains("transportId"))
////                .collect(Collectors.toList());
////        // 3.使用反射,获取字段的值
////        for (Field field : fieldList) {
////            Integer value = (Integer) ReflectUtil.getValue(goodsShip, field.getName());
////            //4.找出值不为0的字段的快递/物流id
////            if (!value.equals(0)) {
////                //存入集合
////                valueList.add(value);
////            }
////        }
////        return Arrays.asList(valueArr);
////        System.out.println(valueList);
////        return valueList;
////    }
//
//        //================================================================================
//        /*
//         * 内部工具方法---从数据库中获取商品对应的商品信息快运方式对象列表，避免重复查询数据库
//         * 如果设置了阈值，会出现两条记录
//         * @param goodsId 商品id
//         * @param entId   仓库id
//         * @return
//         */
//        private List<GoodsShip> getGoodsShipListFromDb(Integer goodsId, Integer entId) throws NoGoosShipFoundException {
//            Example example = new Example(GoodsShip.class);
//            Example.Criteria criteria = example.createCriteria();
//            criteria.andEqualTo("goodsId", goodsId)
//                    .andEqualTo("entId", entId);
//            List<GoodsShip> goodsShipList = goodsShipMapper.selectByExample(example);
//            if (goodsShipList == null || goodsShipList.size() == 0) {
//                throw new NoGoosShipFoundException("该仓库下未查询到符合条件的货运列表！");
//            }
//            return goodsShipList;
//        }
//
////================================================================================
//
//        /**
//         * 启用
//         * 内部方法---根据计价方式（快递/物流的编号）判断是否禁运的公共方法
//         * 由具体子类实现，在抽象类中根据modeId判断快递的类型比较复杂，且扩展性收到影响。
//         *
//         * @param shipId    计价方式id
//         * @param consignee 地区id
//         * @return
//         */
//        abstract public boolean isForbidon(Integer shipId, String consignee) throws NoShipFoundException;
//
//        /**
//         * 根据shipId获取快递对象
//         *
//         * @param shipId
//         * @return
//         */
//        protected Delivery getDelivery(Integer shipId) {
//            return devileryMapper.selectByPrimaryKey(shipId);
//        }
//
//        /**
//         * 根据shipId获取物流对象
//         *
//         * @param shipId
//         * @return
//         */
//        protected Logistics getLogistics(Integer shipId) throws NoShipFoundException {
//            return logisticsMapper.selectByPrimaryKey(shipId);
//        }
//    }

}
